/*
 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 * <p>These classes are designed to be used while the
 * corresponding <code>LookAndFeel</code> class has been installed
 * (<code>UIManager.setLookAndFeel(new <i>XXX</i>LookAndFeel())</code>).
 * Using them while a different <code>LookAndFeel</code> is installed
 * may produce unexpected results, including exceptions.
 * Additionally, changing the <code>LookAndFeel</code>
 * maintained by the <code>UIManager</code> without updating the
 * corresponding <code>ComponentUI</code> of any
 * <code>JComponent</code>s may also produce unexpected results,
 * such as the wrong colors showing up, and is generally not
 * encouraged.
 *
 */

package com.sun.java.swing.plaf.windows;

import java.awt.*;
import java.util.*;

import javax.swing.*;

import sun.awt.windows.ThemeReader;

/**
 * Implements Windows Parts and their States and Properties for the Windows Look and Feel.
 *
 * See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
 * See tmschema.h (or vssym32.h & vsstyle.h for MS Vista)
 *
 * @author Leif Samuelsson
 */
class TMSchema {

    /**
     * An enumeration of the various Windows controls (also known as
     * components, or top-level parts)
     */
    public static enum Control {
        BUTTON, COMBOBOX, EDIT, HEADER, LISTBOX, LISTVIEW, MENU, PROGRESS, REBAR, SCROLLBAR, SPIN, TAB, TOOLBAR, TRACKBAR, TREEVIEW, WINDOW
    }

    /**
     * An enumeration of the Windows compoent parts
     */
    public static enum Part {
        MENU(Control.MENU, 0), // Special case, not in native
        MP_BARBACKGROUND(Control.MENU, 7), MP_BARITEM(Control.MENU, 8), MP_POPUPBACKGROUND(Control.MENU, 9), MP_POPUPBORDERS(Control.MENU, 10), MP_POPUPCHECK(Control.MENU, 11), MP_POPUPCHECKBACKGROUND(Control.MENU, 12), MP_POPUPGUTTER(Control.MENU, 13), MP_POPUPITEM(Control.MENU, 14), MP_POPUPSEPARATOR(Control.MENU, 15), MP_POPUPSUBMENU(Control.MENU, 16),

        BP_PUSHBUTTON(Control.BUTTON, 1), BP_RADIOBUTTON(Control.BUTTON, 2), BP_CHECKBOX(Control.BUTTON, 3), BP_GROUPBOX(Control.BUTTON, 4),

        CP_COMBOBOX(Control.COMBOBOX, 0), CP_DROPDOWNBUTTON(Control.COMBOBOX, 1), CP_BACKGROUND(Control.COMBOBOX, 2), CP_TRANSPARENTBACKGROUND(Control.COMBOBOX, 3), CP_BORDER(Control.COMBOBOX, 4), CP_READONLY(Control.COMBOBOX, 5), CP_DROPDOWNBUTTONRIGHT(Control.COMBOBOX, 6), CP_DROPDOWNBUTTONLEFT(Control.COMBOBOX, 7), CP_CUEBANNER(Control.COMBOBOX, 8),

        EP_EDIT(Control.EDIT, 0), EP_EDITTEXT(Control.EDIT, 1),

        HP_HEADERITEM(Control.HEADER, 1), HP_HEADERSORTARROW(Control.HEADER, 4),

        LBP_LISTBOX(Control.LISTBOX, 0),

        LVP_LISTVIEW(Control.LISTVIEW, 0),

        PP_PROGRESS(Control.PROGRESS, 0), PP_BAR(Control.PROGRESS, 1), PP_BARVERT(Control.PROGRESS, 2), PP_CHUNK(Control.PROGRESS, 3), PP_CHUNKVERT(Control.PROGRESS, 4),

        RP_GRIPPER(Control.REBAR, 1), RP_GRIPPERVERT(Control.REBAR, 2),

        SBP_SCROLLBAR(Control.SCROLLBAR, 0), SBP_ARROWBTN(Control.SCROLLBAR, 1), SBP_THUMBBTNHORZ(Control.SCROLLBAR, 2), SBP_THUMBBTNVERT(Control.SCROLLBAR, 3), SBP_LOWERTRACKHORZ(Control.SCROLLBAR, 4), SBP_UPPERTRACKHORZ(Control.SCROLLBAR, 5), SBP_LOWERTRACKVERT(Control.SCROLLBAR, 6), SBP_UPPERTRACKVERT(Control.SCROLLBAR, 7), SBP_GRIPPERHORZ(Control.SCROLLBAR, 8), SBP_GRIPPERVERT(Control.SCROLLBAR, 9), SBP_SIZEBOX(Control.SCROLLBAR, 10),

        SPNP_UP(Control.SPIN, 1), SPNP_DOWN(Control.SPIN, 2),

        TABP_TABITEM(Control.TAB, 1), TABP_TABITEMLEFTEDGE(Control.TAB, 2), TABP_TABITEMRIGHTEDGE(Control.TAB, 3), TABP_PANE(Control.TAB, 9),

        TP_TOOLBAR(Control.TOOLBAR, 0), TP_BUTTON(Control.TOOLBAR, 1), TP_SEPARATOR(Control.TOOLBAR, 5), TP_SEPARATORVERT(Control.TOOLBAR, 6),

        TKP_TRACK(Control.TRACKBAR, 1), TKP_TRACKVERT(Control.TRACKBAR, 2), TKP_THUMB(Control.TRACKBAR, 3), TKP_THUMBBOTTOM(Control.TRACKBAR, 4), TKP_THUMBTOP(Control.TRACKBAR, 5), TKP_THUMBVERT(Control.TRACKBAR, 6), TKP_THUMBLEFT(Control.TRACKBAR, 7), TKP_THUMBRIGHT(Control.TRACKBAR, 8), TKP_TICS(Control.TRACKBAR, 9), TKP_TICSVERT(Control.TRACKBAR, 10),

        TVP_TREEVIEW(Control.TREEVIEW, 0), TVP_GLYPH(Control.TREEVIEW, 2),

        WP_WINDOW(Control.WINDOW, 0), WP_CAPTION(Control.WINDOW, 1), WP_MINCAPTION(Control.WINDOW, 3), WP_MAXCAPTION(Control.WINDOW, 5), WP_FRAMELEFT(Control.WINDOW, 7), WP_FRAMERIGHT(Control.WINDOW, 8), WP_FRAMEBOTTOM(Control.WINDOW, 9), WP_SYSBUTTON(Control.WINDOW, 13), WP_MDISYSBUTTON(Control.WINDOW, 14), WP_MINBUTTON(Control.WINDOW, 15), WP_MDIMINBUTTON(Control.WINDOW, 16), WP_MAXBUTTON(Control.WINDOW, 17), WP_CLOSEBUTTON(Control.WINDOW, 18), WP_MDICLOSEBUTTON(Control.WINDOW, 20), WP_RESTOREBUTTON(Control.WINDOW, 21), WP_MDIRESTOREBUTTON(Control.WINDOW, 22);

        private final Control control;
        private final int value;

        private Part(Control control, int value) {
            this.control = control;
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public String getControlName(Component component) {
            String str = "";
            if (component instanceof JComponent) {
                JComponent c = (JComponent) component;
                String subAppName = (String) c.getClientProperty("XPStyle.subAppName");
                if (subAppName != null) {
                    str = subAppName + "::";
                }
            }
            return str + control.toString();
        }

        public String toString() {
            return control.toString() + "." + name();
        }
    }

    /**
     * An enumeration of the possible component states
     */
    public static enum State {
        ACTIVE, ASSIST, BITMAP, CHECKED, CHECKEDDISABLED, CHECKEDHOT, CHECKEDNORMAL, CHECKEDPRESSED, CHECKMARKNORMAL, CHECKMARKDISABLED, BULLETNORMAL, BULLETDISABLED, CLOSED, DEFAULTED, DISABLED, DISABLEDHOT, DISABLEDPUSHED, DOWNDISABLED, DOWNHOT, DOWNNORMAL, DOWNPRESSED, FOCUSED, HOT, HOTCHECKED, ICONHOT, ICONNORMAL, ICONPRESSED, ICONSORTEDHOT, ICONSORTEDNORMAL, ICONSORTEDPRESSED, INACTIVE, INACTIVENORMAL, // See note 1
        INACTIVEHOT, // See note 1
        INACTIVEPUSHED, // See note 1
        INACTIVEDISABLED, // See note 1
        LEFTDISABLED, LEFTHOT, LEFTNORMAL, LEFTPRESSED, MIXEDDISABLED, MIXEDHOT, MIXEDNORMAL, MIXEDPRESSED, NORMAL, PRESSED, OPENED, PUSHED, READONLY, RIGHTDISABLED, RIGHTHOT, RIGHTNORMAL, RIGHTPRESSED, SELECTED, UNCHECKEDDISABLED, UNCHECKEDHOT, UNCHECKEDNORMAL, UNCHECKEDPRESSED, UPDISABLED, UPHOT, UPNORMAL, UPPRESSED, HOVER, UPHOVER, DOWNHOVER, LEFTHOVER, RIGHTHOVER, SORTEDDOWN, SORTEDHOT, SORTEDNORMAL, SORTEDPRESSED, SORTEDUP;

        /**
         * A map of allowed states for each Part
         */
        private static EnumMap<Part, State[]> stateMap;

        private static synchronized void initStates() {
            stateMap = new EnumMap<Part, State[]>(Part.class);

            stateMap.put(Part.EP_EDITTEXT, new State[] { NORMAL, HOT, SELECTED, DISABLED, FOCUSED, READONLY, ASSIST });

            stateMap.put(Part.BP_PUSHBUTTON, new State[] { NORMAL, HOT, PRESSED, DISABLED, DEFAULTED });

            stateMap.put(Part.BP_RADIOBUTTON, new State[] { UNCHECKEDNORMAL, UNCHECKEDHOT, UNCHECKEDPRESSED, UNCHECKEDDISABLED, CHECKEDNORMAL, CHECKEDHOT, CHECKEDPRESSED, CHECKEDDISABLED });

            stateMap.put(Part.BP_CHECKBOX, new State[] { UNCHECKEDNORMAL, UNCHECKEDHOT, UNCHECKEDPRESSED, UNCHECKEDDISABLED, CHECKEDNORMAL, CHECKEDHOT, CHECKEDPRESSED, CHECKEDDISABLED, MIXEDNORMAL, MIXEDHOT, MIXEDPRESSED, MIXEDDISABLED });

            State[] comboBoxStates = new State[] { NORMAL, HOT, PRESSED, DISABLED };
            stateMap.put(Part.CP_COMBOBOX, comboBoxStates);
            stateMap.put(Part.CP_DROPDOWNBUTTON, comboBoxStates);
            stateMap.put(Part.CP_BACKGROUND, comboBoxStates);
            stateMap.put(Part.CP_TRANSPARENTBACKGROUND, comboBoxStates);
            stateMap.put(Part.CP_BORDER, comboBoxStates);
            stateMap.put(Part.CP_READONLY, comboBoxStates);
            stateMap.put(Part.CP_DROPDOWNBUTTONRIGHT, comboBoxStates);
            stateMap.put(Part.CP_DROPDOWNBUTTONLEFT, comboBoxStates);
            stateMap.put(Part.CP_CUEBANNER, comboBoxStates);

            stateMap.put(Part.HP_HEADERITEM, new State[] { NORMAL, HOT, PRESSED, SORTEDNORMAL, SORTEDHOT, SORTEDPRESSED, ICONNORMAL, ICONHOT, ICONPRESSED, ICONSORTEDNORMAL, ICONSORTEDHOT, ICONSORTEDPRESSED });

            stateMap.put(Part.HP_HEADERSORTARROW, new State[] { SORTEDDOWN, SORTEDUP });

            State[] scrollBarStates = new State[] { NORMAL, HOT, PRESSED, DISABLED, HOVER };
            stateMap.put(Part.SBP_SCROLLBAR, scrollBarStates);
            stateMap.put(Part.SBP_THUMBBTNVERT, scrollBarStates);
            stateMap.put(Part.SBP_THUMBBTNHORZ, scrollBarStates);
            stateMap.put(Part.SBP_GRIPPERVERT, scrollBarStates);
            stateMap.put(Part.SBP_GRIPPERHORZ, scrollBarStates);

            stateMap.put(Part.SBP_ARROWBTN, new State[] { UPNORMAL, UPHOT, UPPRESSED, UPDISABLED, DOWNNORMAL, DOWNHOT, DOWNPRESSED, DOWNDISABLED, LEFTNORMAL, LEFTHOT, LEFTPRESSED, LEFTDISABLED, RIGHTNORMAL, RIGHTHOT, RIGHTPRESSED, RIGHTDISABLED, UPHOVER, DOWNHOVER, LEFTHOVER, RIGHTHOVER });

            State[] spinnerStates = new State[] { NORMAL, HOT, PRESSED, DISABLED };
            stateMap.put(Part.SPNP_UP, spinnerStates);
            stateMap.put(Part.SPNP_DOWN, spinnerStates);

            stateMap.put(Part.TVP_GLYPH, new State[] { CLOSED, OPENED });

            State[] frameButtonStates = new State[] { NORMAL, HOT, PUSHED, DISABLED, // See note 1
            INACTIVENORMAL, INACTIVEHOT, INACTIVEPUSHED, INACTIVEDISABLED, };
            // Note 1: The INACTIVE frame button states apply when the frame
            //         is inactive. They are not defined in tmschema.h

            // Fix for 6316538: Vista has five frame button states
            if (ThemeReader.getInt(Control.WINDOW.toString(), Part.WP_CLOSEBUTTON.getValue(), 1, Prop.IMAGECOUNT.getValue()) == 10) {
                frameButtonStates = new State[] { NORMAL, HOT, PUSHED, DISABLED, null, INACTIVENORMAL, INACTIVEHOT, INACTIVEPUSHED, INACTIVEDISABLED, null };
            }

            stateMap.put(Part.WP_MINBUTTON, frameButtonStates);
            stateMap.put(Part.WP_MAXBUTTON, frameButtonStates);
            stateMap.put(Part.WP_RESTOREBUTTON, frameButtonStates);
            stateMap.put(Part.WP_CLOSEBUTTON, frameButtonStates);

            // States for Slider (trackbar)
            stateMap.put(Part.TKP_TRACK, new State[] { NORMAL });
            stateMap.put(Part.TKP_TRACKVERT, new State[] { NORMAL });

            State[] sliderThumbStates = new State[] { NORMAL, HOT, PRESSED, FOCUSED, DISABLED };
            stateMap.put(Part.TKP_THUMB, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBBOTTOM, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBTOP, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBVERT, sliderThumbStates);
            stateMap.put(Part.TKP_THUMBRIGHT, sliderThumbStates);

            // States for Tabs
            State[] tabStates = new State[] { NORMAL, HOT, SELECTED, DISABLED, FOCUSED };
            stateMap.put(Part.TABP_TABITEM, tabStates);
            stateMap.put(Part.TABP_TABITEMLEFTEDGE, tabStates);
            stateMap.put(Part.TABP_TABITEMRIGHTEDGE, tabStates);

            stateMap.put(Part.TP_BUTTON, new State[] { NORMAL, HOT, PRESSED, DISABLED, CHECKED, HOTCHECKED });

            State[] frameStates = new State[] { ACTIVE, INACTIVE };
            stateMap.put(Part.WP_WINDOW, frameStates);
            stateMap.put(Part.WP_FRAMELEFT, frameStates);
            stateMap.put(Part.WP_FRAMERIGHT, frameStates);
            stateMap.put(Part.WP_FRAMEBOTTOM, frameStates);

            State[] captionStates = new State[] { ACTIVE, INACTIVE, DISABLED };
            stateMap.put(Part.WP_CAPTION, captionStates);
            stateMap.put(Part.WP_MINCAPTION, captionStates);
            stateMap.put(Part.WP_MAXCAPTION, captionStates);

            stateMap.put(Part.MP_BARBACKGROUND, new State[] { ACTIVE, INACTIVE });
            stateMap.put(Part.MP_BARITEM, new State[] { NORMAL, HOT, PUSHED, DISABLED, DISABLEDHOT, DISABLEDPUSHED });
            stateMap.put(Part.MP_POPUPCHECK, new State[] { CHECKMARKNORMAL, CHECKMARKDISABLED, BULLETNORMAL, BULLETDISABLED });
            stateMap.put(Part.MP_POPUPCHECKBACKGROUND, new State[] { DISABLEDPUSHED, NORMAL, BITMAP });
            stateMap.put(Part.MP_POPUPITEM, new State[] { NORMAL, HOT, DISABLED, DISABLEDHOT });
            stateMap.put(Part.MP_POPUPSUBMENU, new State[] { NORMAL, DISABLED });

        }

        public static synchronized int getValue(Part part, State state) {
            if (stateMap == null) {
                initStates();
            }

            Enum[] states = stateMap.get(part);
            if (states != null) {
                for (int i = 0; i < states.length; i++) {
                    if (state == states[i]) {
                        return i + 1;
                    }
                }
            }

            if (state == null || state == State.NORMAL) {
                return 1;
            }

            return 0;
        }

    }

    /**
     * An enumeration of the possible component attributes and the
     * corresponding value type
     */
    public static enum Prop {
        COLOR(Color.class, 204), SIZE(Dimension.class, 207),

        FLATMENUS(Boolean.class, 1001),

        BORDERONLY(Boolean.class, 2203), // only draw the border area of the image

        IMAGECOUNT(Integer.class, 2401), // the number of state images in an imagefile
        BORDERSIZE(Integer.class, 2403), // the size of the border line for bgtype=BorderFill

        PROGRESSCHUNKSIZE(Integer.class, 2411), // size of progress control chunks
        PROGRESSSPACESIZE(Integer.class, 2412), // size of progress control spaces

        TEXTSHADOWOFFSET(Point.class, 3402), // where char shadows are drawn, relative to orig. chars

        NORMALSIZE(Dimension.class, 3409), // size of dest rect that exactly source

        SIZINGMARGINS(Insets.class, 3601), // margins used for 9-grid sizing
        CONTENTMARGINS(Insets.class, 3602), // margins that define where content can be placed
        CAPTIONMARGINS(Insets.class, 3603), // margins that define where caption text can be placed

        BORDERCOLOR(Color.class, 3801), // color of borders for BorderFill
        FILLCOLOR(Color.class, 3802), // color of bg fill
        TEXTCOLOR(Color.class, 3803), // color text is drawn in

        TEXTSHADOWCOLOR(Color.class, 3818), // color of text shadow

        BGTYPE(Integer.class, 4001), // basic drawing type for each part

        TEXTSHADOWTYPE(Integer.class, 4010), // type of shadow to draw with text

        TRANSITIONDURATIONS(Integer.class, 6000);

        private final Class type;
        private final int value;

        private Prop(Class type, int value) {
            this.type = type;
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public String toString() {
            return name() + "[" + type.getName() + "] = " + value;
        }
    }

    /**
     * An enumeration of attribute values for some Props
     */
    public static enum TypeEnum {
        BT_IMAGEFILE(Prop.BGTYPE, "imagefile", 0), BT_BORDERFILL(Prop.BGTYPE, "borderfill", 1),

        TST_NONE(Prop.TEXTSHADOWTYPE, "none", 0), TST_SINGLE(Prop.TEXTSHADOWTYPE, "single", 1), TST_CONTINUOUS(Prop.TEXTSHADOWTYPE, "continuous", 2);

        private TypeEnum(Prop prop, String enumName, int value) {
            this.prop = prop;
            this.enumName = enumName;
            this.value = value;
        }

        private final Prop prop;
        private final String enumName;
        private final int value;

        public String toString() {
            return prop + "=" + enumName + "=" + value;
        }

        String getName() {
            return enumName;
        }

        static TypeEnum getTypeEnum(Prop prop, int enumval) {
            for (TypeEnum e : TypeEnum.values()) {
                if (e.prop == prop && e.value == enumval) {
                    return e;
                }
            }
            return null;
        }
    }
}
